{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE LambdaCase #-}

module Aria2.Error where

import Data.Aeson (FromJSON (..), withScientific)
import Data.Scientific (toBoundedInteger)
import Optics.AffineFold (preview)
import Optics.Prism (Prism', prism')

-- Based on https://aria2.github.io/manual/en/html/aria2c.html#exit-status
data Aria2Error
  = UnknownError
  | TimeOut
  | ResourceNotFound
  | SawSpecifiedResourceNotFound
  | DownloadSpeedTooSlow
  | NetworkProblem
  | UnfinishedDownloadsOnExit
  | ResumeNotSupported
  | NotEnoughDiskSpace
  | PieceLengthDifferent
  | AlreadyDownloadingFile
  | AlreadyDownloadingInfoHash
  | FileAlreadyExists
  | FileRenamingFailed
  | CouldNotOpenFile
  | CouldNotCreateOrTruncateFile
  | FileIOError
  | CouldNotCreateDirectory
  | NameResolutionFailed
  | CouldNotParseMetalinkDocument
  | FTPCommandFailed
  | HTTPResponseHeaderBad
  | TooManyRedirects
  | HTTPAuthorizationFailed
  | CouldNotParseBencodedFile
  | TorrentFileCorrupted
  | BadMagnetURI
  | UnexpectedOption
  | ServerOverloaded
  | CouldNotParseJSONRPC
  | ChecksumFailed
  deriving stock (Eq, Show)

errorCode :: Prism' Word Aria2Error
errorCode = prism' intoErrCode outOfErrCode
  where
    intoErrCode = \case
      UnknownError -> 1
      TimeOut -> 2
      ResourceNotFound -> 3
      SawSpecifiedResourceNotFound -> 4
      DownloadSpeedTooSlow -> 5
      NetworkProblem -> 6
      UnfinishedDownloadsOnExit -> 7
      ResumeNotSupported -> 8
      NotEnoughDiskSpace -> 9
      PieceLengthDifferent -> 10
      AlreadyDownloadingFile -> 11
      AlreadyDownloadingInfoHash -> 12
      FileAlreadyExists -> 13
      FileRenamingFailed -> 14
      CouldNotOpenFile -> 15
      CouldNotCreateOrTruncateFile -> 16
      FileIOError -> 17
      CouldNotCreateDirectory -> 18
      NameResolutionFailed -> 19
      CouldNotParseMetalinkDocument -> 20
      FTPCommandFailed -> 21
      HTTPResponseHeaderBad -> 22
      TooManyRedirects -> 23
      HTTPAuthorizationFailed -> 24
      CouldNotParseBencodedFile -> 25
      TorrentFileCorrupted -> 26
      BadMagnetURI -> 27
      UnexpectedOption -> 28
      ServerOverloaded -> 29
      CouldNotParseJSONRPC -> 30
      ChecksumFailed -> 32
    outOfErrCode = \case
      1 -> Just UnknownError
      2 -> Just TimeOut
      3 -> Just ResourceNotFound
      4 -> Just SawSpecifiedResourceNotFound
      5 -> Just DownloadSpeedTooSlow
      6 -> Just NetworkProblem
      7 -> Just UnfinishedDownloadsOnExit
      8 -> Just ResumeNotSupported
      9 -> Just NotEnoughDiskSpace
      10 -> Just PieceLengthDifferent
      11 -> Just AlreadyDownloadingFile
      12 -> Just AlreadyDownloadingInfoHash
      13 -> Just FileAlreadyExists
      14 -> Just FileRenamingFailed
      15 -> Just CouldNotOpenFile
      16 -> Just CouldNotCreateOrTruncateFile
      17 -> Just FileIOError
      18 -> Just CouldNotCreateDirectory
      19 -> Just NameResolutionFailed
      20 -> Just CouldNotParseMetalinkDocument
      21 -> Just FTPCommandFailed
      22 -> Just HTTPResponseHeaderBad
      23 -> Just TooManyRedirects
      24 -> Just HTTPAuthorizationFailed
      25 -> Just CouldNotParseBencodedFile
      26 -> Just TorrentFileCorrupted
      27 -> Just BadMagnetURI
      28 -> Just UnexpectedOption
      29 -> Just ServerOverloaded
      30 -> Just CouldNotParseJSONRPC
      32 -> Just ChecksumFailed
      _ -> Nothing

instance FromJSON Aria2Error where
  parseJSON = withScientific "Aria2Error" go
    where
      go s = case toBoundedInteger s >>= preview errorCode of
        Nothing -> fail ("Not a valid error code: " <> show s)
        Just err -> pure err
